﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Configuration;
using System.Collections;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.Utility;
using BIM.XML3DExport;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Diagnostics;
using GeometryOptions = Autodesk.Revit.DB.Options;
using RevitView = Autodesk.Revit.DB.View;
using Autodesk.Revit.DB.Structure;

using System.Windows.Forms;

namespace BIM.XML3DExport
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)]
    public class XML3DExportCommand : IExternalCommand
    {
        private readonly XML3DGenerator generator = new XML3DGenerator();
        private string xml3DfoldPath = null;
        private int elementIdx = 0;
        private GeometryOptions m_ViewOptions;
        private Document m_ActiveDocument;
        Dictionary<ElementId, Color> mapOverrideEleIdColor = new Dictionary<ElementId, Color>();

        #region IExternalCommand Members
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                InitialData();

                UIApplication app = commandData.Application;

                Document doc = app.ActiveUIDocument.Document;
                generator.m_ActiveDocument = doc;
                m_ActiveDocument = doc;
                m_ViewOptions = app.Application.Create.NewGeometryOptions();
                m_ViewOptions.View = doc.ActiveView;
                Find3DView(doc);
                Transaction trans = new Transaction(doc, "ExComm");

                // Select some elements in Revit before invoking this command
                // Get the handle of current document.
                UIDocument uidoc = commandData.Application.ActiveUIDocument;
                // Get the element selection of current document.
                Selection selection = uidoc.Selection;
                ElementSet collection = selection.Elements;

                // 10/16/2013 mwu : extract view filter information, and insert to a Dictionary
                Autodesk.Revit.DB.View view = m_ActiveDocument.ActiveView;
                ICollection<ElementId> filters = view.GetFilters();
                foreach (ElementId id in filters)
                {
                    ParameterFilterElement parameterFilterElement = doc.GetElement(id) as ParameterFilterElement;
                    OverrideGraphicSettings os = view.GetFilterOverrides(id);
                    if (parameterFilterElement != null && os != null && os.IsProjectionFillPatternVisible)
                    {
                        Color col = os.ProjectionFillColor;
                        FilteredElementCollector parameterCollector = new FilteredElementCollector(doc/*, doc.ActiveView.Id*/);
                        if (parameterCollector != null && col != null)
                        {
                            ICollection<ElementId> categoryIds = parameterFilterElement.GetCategories();

                            FilterCategoryRule categoryRule = new FilterCategoryRule(categoryIds);

                            ElementParameterFilter categoryFilter = new ElementParameterFilter(categoryRule);
                            parameterCollector = parameterCollector.WherePasses(categoryFilter);

                            //check if there is other rules applied rather than categoryFilter
                            IList<FilterRule> filterRules = parameterFilterElement.GetRules();
                            if (filterRules.Count > 0 && col.IsValid)
                            {
                                ElementParameterFilter filter = new ElementParameterFilter(filterRules);
                                parameterCollector = parameterCollector.WherePasses(filter);
                                ICollection<ElementId> filteredElemIds = parameterCollector.ToElementIds();
                                foreach (ElementId elemId in filteredElemIds)
                                {
                                    if (mapOverrideEleIdColor.ContainsKey(elemId) && col.IsValid)//override the old color
                                    {
                                        mapOverrideEleIdColor[elemId] = col;
                                    }
                                    else
                                    {
                                        mapOverrideEleIdColor.Add(elemId, col);
                                    }
                                }
                            }
                            else // 10/23/2013 mwu : there is no other filters 
                            {
                                ICollection<ElementId> elemIds = parameterCollector.ToElementIds();
                                foreach (ElementId elemId in elemIds)
                                {
                                    if (!mapOverrideEleIdColor.ContainsKey(elemId) && col.IsValid)
                                    {
                                        mapOverrideEleIdColor.Add(elemId, col);
                                    }
                                }
                            }
                        }
                    }
                }

                if (0 == collection.Size) // If no elements selected.
                {
                    // 11/1/2013 mwu :  TaskDialog.Show("Revit", "即将导出模型中所有实体。");
                    SaveAllVisibleElements(app);
                }
                else
                {
                    // 11/1/2013 mwu :  TaskDialog.Show("Revit", "即将导出选中的模型。");
                    SaveSelectedElements(collection);
                }
            }
            //  throw new NotImplementedException();
            catch (Exception e)
            {
                message = e.Message;
                return Result.Failed;
            }
            return Result.Succeeded;
        }
        #endregion IExternalCommand Members

        void InitialData()
        {
            elementIdx = 1;
            string AddInPath = BIM.XML3DExport.XML3DExportUI.AddInPath;
            string directoryName = Path.GetDirectoryName(AddInPath);
            //string directoryName = "D:\\";
            xml3DfoldPath = directoryName + @"\3DXML";

            if (!Directory.Exists(xml3DfoldPath))
            {
                Directory.CreateDirectory(xml3DfoldPath);
            }
            else
            {
                DirectoryInfo di = new DirectoryInfo(xml3DfoldPath);
                di.Delete(true);
                Directory.CreateDirectory(xml3DfoldPath);
            }
        }

        private void Find3DView(Document doc)
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc).OfClass(typeof(RevitView));

            IEnumerable<RevitView> viewEnum
              = collector.ToElements().Cast<RevitView>();
            bool bHasData = false;
            foreach (RevitView view in viewEnum)
            {
                View3D curView3D = view as View3D;
                if (curView3D != null && curView3D.Name == "{3D}")
                {
                    XYZ position = curView3D.Origin;
                    XYZ right = curView3D.RightDirection;
                    XYZ up = curView3D.UpDirection;
                    XYZ sight = curView3D.ViewDirection;
                    generator.viewPosition = position;
                    generator.viewRightDir = right;
                    generator.viewUpDir = up;
                    generator.viewDirection = -sight;
                    bHasData = true;
                }
            }
            if (!bHasData)
            {
                foreach (RevitView view in viewEnum)
                {
                    RevitView curView3D = view;
                    if (curView3D != null)
                    {
                        XYZ position = curView3D.Origin;
                        XYZ right = curView3D.RightDirection;
                        XYZ up = curView3D.UpDirection;
                        XYZ sight = curView3D.ViewDirection;
                        generator.viewPosition = position;
                        generator.viewRightDir = right;
                        generator.viewUpDir = up;
                        generator.viewDirection = -sight;
                        bHasData = true;
                    }
                }
            }
        }

        private ElementId FindActiveView(Document doc, string activeViewName)
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            collector.OfClass(typeof(RevitView));

            IEnumerable<Element> selectedView = from view in collector.ToList<Element>()
                                                where view.Name == activeViewName
                                                select view;

            if (selectedView.Count() > 0)
            {
                return (selectedView.First() as RevitView).Id;
            }

            return ElementId.InvalidElementId;
        }
        
        private static double FeetToMm(double val)//毫米到英寸，单位换算
        {
            return val * 304.8;
        }

        private void GetShellNormal(TriangulatedShellComponent shellComponent,
            out String normalListStr)
        {
            int triangleCount = shellComponent.TriangleCount;
            int vertetxCount = shellComponent.VertexCount;
            XYZ[] triPnts = new XYZ[3];
            XYZ normal = new XYZ();
            Hashtable idxNormalTable = new Hashtable();
            normalListStr = null;
            for (int j = 0; j < triangleCount; ++j)
            {
                TriangleInShellComponent curTriangle = shellComponent.GetTriangle(j);
                int idx0 = curTriangle.VertexIndex0;
                int idx1 = curTriangle.VertexIndex1;
                int idx2 = curTriangle.VertexIndex2;
                triPnts[0] = shellComponent.GetVertex(idx0);
                triPnts[1] = shellComponent.GetVertex(idx1);
                triPnts[2] = shellComponent.GetVertex(idx2);
                XYZ pnt1 = triPnts[1] - triPnts[0];
                normal = pnt1.CrossProduct(triPnts[2] - triPnts[0]);
                normal = normal.Normalize();
                if (idxNormalTable.Contains(idx0))
                {
                    XYZ curNormal = idxNormalTable[idx0] as XYZ;
                    idxNormalTable[idx0] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(idx0, normal);
                }
                if (idxNormalTable.Contains(idx1))
                {
                    XYZ curNormal = idxNormalTable[idx1] as XYZ;
                    idxNormalTable[idx1] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(idx1, normal);
                }
                if (idxNormalTable.Contains(idx2))
                {
                    XYZ curNormal = idxNormalTable[idx2] as XYZ;
                    idxNormalTable[idx2] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(idx2, normal);
                }
            }

            for (int i = 0; i < vertetxCount; ++i)
            {
                XYZ curNormal = idxNormalTable[i] as XYZ;
                if (i == 0)
                {
                    normalListStr += String.Format("{0} {1} {2}", curNormal.X,
                        curNormal.Y, curNormal.Z);
                }
                else
                {
                    normalListStr += String.Format(",{0} {1} {2}", curNormal.X,
                        curNormal.Y, curNormal.Z);
                }
            }
        }

        private bool CheckPointOnList(List<XYZ> xyzList, XYZ pnt, out int pntIdx)
        {
            bool bOnList = false;
            pntIdx = -1;
            for (int i = 0; i < xyzList.Count; ++i)
            {
                if (xyzList[i].IsAlmostEqualTo(pnt, 0.00001))
                {
                    pntIdx = i;
                    bOnList = true;
                    break;
                }
            }
            return bOnList;
        }

        private void GetMeshFaceMeshInfo(Mesh mesh, Transform transform,
            out List<String> faceIdxStrList,
            out List<String> vertexStrList,
            out List<String> normalStrList)
        {
            faceIdxStrList = new List<String>();
            vertexStrList = new List<String>();
            normalStrList = new List<String>();

            if (mesh == null)
            {
                return;
            }
            String faceStr = null;
            String vertexStr = null;
            String normalStr = null;

            List<XYZ> xyzList = new List<XYZ>();
            Hashtable idxNormalTable = new Hashtable();

            for (int i = 0; i < mesh.NumTriangles; i++)
            {
                //position
                MeshTriangle triangle = mesh.get_Triangle(i);
                XYZ vertex1 = triangle.get_Vertex(0);
                XYZ vertex2 = triangle.get_Vertex(1);
                XYZ vertex3 = triangle.get_Vertex(2);
                if (transform != null)
                {
                    vertex1 = transform.OfPoint(vertex1);
                    vertex2 = transform.OfPoint(vertex2);
                    vertex3 = transform.OfPoint(vertex3);
                }
                //face index
                int pntIdx1 = -1;
                int pntIdx2 = -1;
                int pntIdx3 = -1;
                if (!CheckPointOnList(xyzList, vertex1, out pntIdx1))
                {
                    xyzList.Add(vertex1);
                    pntIdx1 = xyzList.Count - 1;
                }
                if (!CheckPointOnList(xyzList, vertex2, out pntIdx2))
                {
                    xyzList.Add(vertex2);
                    pntIdx2 = xyzList.Count - 1;
                }
                if (!CheckPointOnList(xyzList, vertex3, out pntIdx3))
                {
                    xyzList.Add(vertex3);
                    pntIdx3 = xyzList.Count - 1;
                }
                if (i == 0)
                {
                    faceStr += String.Format("{0} {1} {2}",
                        pntIdx1, pntIdx2, pntIdx3);
                }
                else
                {
                    faceStr += String.Format(" {0} {1} {2}",
                        pntIdx1, pntIdx2, pntIdx3);
                }
                //Normal String
                XYZ pnt1 = vertex2 - vertex1;
                XYZ normal = pnt1.CrossProduct(vertex3 - vertex1);
                normal = normal.Normalize();
                if (idxNormalTable.Contains(pntIdx1))
                {
                    XYZ curNormal = idxNormalTable[pntIdx1] as XYZ;
                    idxNormalTable[pntIdx1] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(pntIdx1, normal);
                }
                if (idxNormalTable.Contains(pntIdx2))
                {
                    XYZ curNormal = idxNormalTable[pntIdx2] as XYZ;
                    idxNormalTable[pntIdx2] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(pntIdx2, normal);
                }
                if (idxNormalTable.Contains(pntIdx3))
                {
                    XYZ curNormal = idxNormalTable[pntIdx3] as XYZ;
                    idxNormalTable[pntIdx3] = ((curNormal + normal) / 2).Normalize();
                }
                else
                {
                    idxNormalTable.Add(pntIdx3, normal);
                }
            }

            for (int j = 0; j < xyzList.Count; ++j)
            {
                XYZ curPnt = xyzList[j];
                if (j == 0)
                {
                    vertexStr += String.Format("{0} {1} {2}",
                        FeetToMm(curPnt.X), FeetToMm(curPnt.Y), FeetToMm(curPnt.Z));
                }
                else
                {
                    vertexStr += String.Format(",{0} {1} {2}",
                        FeetToMm(curPnt.X), FeetToMm(curPnt.Y), FeetToMm(curPnt.Z));
                }

                XYZ curNormal = idxNormalTable[j] as XYZ;
                if (j == 0)
                {
                    normalStr += String.Format("{0} {1} {2}", curNormal.X,
                        curNormal.Y, curNormal.Z);
                }
                else
                {
                    normalStr += String.Format(",{0} {1} {2}", curNormal.X,
                        curNormal.Y, curNormal.Z);
                }
            }
            faceIdxStrList.Add(faceStr);
            vertexStrList.Add(vertexStr);
            normalStrList.Add(normalStr);
        }

        private bool GetSolidFaceMeshInfo(Solid solid, Transform transform, bool bSolidHasMaterial,
            out List<String> faceIdxStrList,
            out List<String> vertexStrList,
            out List<String> normalStrList)
        {
            bool suc = false;
            faceIdxStrList = new List<String>();
            vertexStrList = new List<String>();
            normalStrList = new List<String>();
            if (solid == null)
            {
                return suc;
            }

            int iHasVertexNum = 0;
            String faceStr = null;
            String vertexStr = null;
            String normalStr = null;
            foreach (Face geomFace in solid.Faces)
            {
                if (!bSolidHasMaterial)
                {
                    faceStr = null;
                    vertexStr = null;
                    normalStr = null;
                }
                // Get mesh
                List<XYZ> xyzList = new List<XYZ>();
                Hashtable idxNormalTable = new Hashtable();

                Mesh mesh = geomFace.Triangulate();
                for (int i = 0; i < mesh.NumTriangles; i++)
                {
                    //position
                    MeshTriangle triangle = mesh.get_Triangle(i);
                    XYZ vertex1 = triangle.get_Vertex(0);
                    XYZ vertex2 = triangle.get_Vertex(1);
                    XYZ vertex3 = triangle.get_Vertex(2);
                    if (transform != null)
                    {
                        vertex1 = transform.OfPoint(vertex1);
                        vertex2 = transform.OfPoint(vertex2);
                        vertex3 = transform.OfPoint(vertex3);
                    }
                    //face index
                    int pntIdx1 = -1;
                    int pntIdx2 = -1;
                    int pntIdx3 = -1;
                    if (!CheckPointOnList(xyzList, vertex1, out pntIdx1))
                    {
                        xyzList.Add(vertex1);
                        pntIdx1 = xyzList.Count - 1;
                    }
                    if (!CheckPointOnList(xyzList, vertex2, out pntIdx2))
                    {
                        xyzList.Add(vertex2);
                        pntIdx2 = xyzList.Count - 1;
                    }
                    if (!CheckPointOnList(xyzList, vertex3, out pntIdx3))
                    {
                        xyzList.Add(vertex3);
                        pntIdx3 = xyzList.Count - 1;
                    }
                    if (iHasVertexNum == 0 && i == 0)
                    {
                        faceStr += String.Format("{0} {1} {2}",
                            pntIdx1, pntIdx2, pntIdx3);
                    }
                    else
                    {
                        faceStr += String.Format(" {0} {1} {2}",
                            pntIdx1 + iHasVertexNum,
                            pntIdx2 + iHasVertexNum,
                            pntIdx3 + iHasVertexNum);
                    }
                    //Normal String
                    XYZ pnt1 = vertex2 - vertex1;
                    XYZ normal = pnt1.CrossProduct(vertex3 - vertex1);
                    normal = normal.Normalize();
                    if (idxNormalTable.Contains(pntIdx1))
                    {
                        XYZ curNormal = idxNormalTable[pntIdx1] as XYZ;
                        idxNormalTable[pntIdx1] = ((curNormal + normal) / 2).Normalize();
                    }
                    else
                    {
                        idxNormalTable.Add(pntIdx1, normal);
                    }
                    if (idxNormalTable.Contains(pntIdx2))
                    {
                        XYZ curNormal = idxNormalTable[pntIdx2] as XYZ;
                        idxNormalTable[pntIdx2] = ((curNormal + normal) / 2).Normalize();
                    }
                    else
                    {
                        idxNormalTable.Add(pntIdx2, normal);
                    }
                    if (idxNormalTable.Contains(pntIdx3))
                    {
                        XYZ curNormal = idxNormalTable[pntIdx3] as XYZ;
                        idxNormalTable[pntIdx3] = ((curNormal + normal) / 2).Normalize();
                    }
                    else
                    {
                        idxNormalTable.Add(pntIdx3, normal);
                    }
                }
                for (int j = 0; j < xyzList.Count; ++j)
                {
                    XYZ curPnt = xyzList[j];
                    if (iHasVertexNum == 0 && j == 0)
                    {
                        vertexStr += String.Format("{0:f} {1:f} {2:f}",
                            FeetToMm(curPnt.X), FeetToMm(curPnt.Y), FeetToMm(curPnt.Z));
                    }
                    else
                    {
                        vertexStr += String.Format(",{0:f} {1:f} {2:f}",
                            FeetToMm(curPnt.X), FeetToMm(curPnt.Y), FeetToMm(curPnt.Z));
                    }

                    XYZ curNormal = idxNormalTable[j] as XYZ;
                    if (iHasVertexNum == 0 && j == 0)
                    {
                        normalStr += String.Format("{0:f} {1:f} {2:f}", curNormal.X,
                            curNormal.Y, curNormal.Z);
                    }
                    else
                    {
                        normalStr += String.Format(",{0:f} {1:f} {2:f}", curNormal.X,
                            curNormal.Y, curNormal.Z);
                    }
                }
                if (!bSolidHasMaterial)
                {
                    if (faceStr != null &&
                        vertexStrList != null)
                    {
                        faceIdxStrList.Add(faceStr);
                        vertexStrList.Add(vertexStr);
                        normalStrList.Add(normalStr);
                    }
                    iHasVertexNum = 0;
                }
                else
                {
                    iHasVertexNum += xyzList.Count;
                }
            }
            if (bSolidHasMaterial)
            {
                if (faceStr != null &&
                    vertexStrList != null)
                {
                    faceIdxStrList.Add(faceStr);
                    vertexStrList.Add(vertexStr);
                    normalStrList.Add(normalStr);
                }
            }

            return suc;
        }

        //private bool GetSolidFaceMeshInfoNew(Solid solid, Transform transform,
        //      out List<String> faceIdxStrList,
        //      out List<String> vertexStrList,
        //      out List<String> normalStrList)
        //{
        //    bool suc = false;
        //    faceIdxStrList = new List<String>();
        //    vertexStrList = new List<String>();
        //    normalStrList = new List<String>();
        //    if (solid == null)
        //    {
        //        return suc;
        //    }

        //    String faceStr = null;
        //    String vertexStr = null;
        //    String normalStr = null;

        //    int orgVertexNum = 0;
        //    int vertexNum;

        //    GetSolidFacetInfo(solid, transform, orgVertexNum, out vertexNum, out faceStr, out vertexStr, out normalStr);

        //    if (faceStr != null &&
        //        vertexStr != null)
        //    {
        //        faceIdxStrList.Add(faceStr);
        //        vertexStrList.Add(vertexStr);
        //        normalStrList.Add(normalStr);
        //    }
        //    return suc;
        //}

        //private bool GetSolidFacetInfo(Solid solid, Transform transform,
        //    int orgVertexNum, out int vertexNum,
        //    out String triangleIdxListStr,
        //    out String vertexPositionListStr,
        //    out String vertexNormalListStr)
        //{
        //    bool suc = false;
        //    vertexNum = 0;
        //    triangleIdxListStr = null;
        //    vertexPositionListStr = null;
        //    vertexNormalListStr = null;
        //    if (solid == null)
        //    {
        //        return suc;
        //    }
        //    triangleIdxListStr = null;
        //    vertexPositionListStr = null;
        //    if (!SolidUtils.IsValidForTessellation(solid))
        //    {
        //        return suc;
        //    }
        //    SolidOrShellTessellationControls tessControl = new SolidOrShellTessellationControls();
        //    tessControl.LevelOfDetail = 0.5;
        //    TriangulatedSolidOrShell shellData = SolidUtils.TessellateSolidOrShell(solid, tessControl);
        //    int shellNum = shellData.ShellComponentCount;
        //    for (int i = 0; i < shellNum; ++i)
        //    {
        //        TriangulatedShellComponent shellComponent = shellData.GetShellComponent(i);
        //        String curNormalStr = null;
        //        GetShellNormal(shellComponent, out curNormalStr);
        //        int triangleCount = shellComponent.TriangleCount;
        //        int vertetxCount = shellComponent.VertexCount;
        //        /// <summary>
        //        for (int j = 0; j < triangleCount; ++j)
        //        {
        //            TriangleInShellComponent curTriangle = shellComponent.GetTriangle(j);
        //            if (i == 0 && j == 0)
        //            {
        //                triangleIdxListStr += String.Format("{0} {1} {2}",
        //                    curTriangle.VertexIndex0 + orgVertexNum,
        //                    curTriangle.VertexIndex1 + orgVertexNum,
        //                    curTriangle.VertexIndex2 + orgVertexNum);
        //            }
        //            else
        //            {
        //                triangleIdxListStr += String.Format(" {0} {1} {2}",
        //                    curTriangle.VertexIndex0 + orgVertexNum,
        //                    curTriangle.VertexIndex1 + orgVertexNum,
        //                    curTriangle.VertexIndex2 + orgVertexNum);
        //            }
        //        }
        //        for (int k = 0; k < vertetxCount; ++k)
        //        {
        //            XYZ curVeretx = shellComponent.GetVertex(k);
        //            if (transform != null)
        //            {
        //                curVeretx = transform.OfPoint(curVeretx);
        //            }
        //            if (i == 0 && k == 0)
        //            {
        //                vertexPositionListStr += String.Format("{0} {1} {2}", FeetToMm(curVeretx.X),
        //                    FeetToMm(curVeretx.Y), FeetToMm(curVeretx.Z));
        //            }
        //            else
        //            {
        //                vertexPositionListStr += String.Format(",{0} {1} {2}", FeetToMm(curVeretx.X),
        //                    FeetToMm(curVeretx.Y), FeetToMm(curVeretx.Z));
        //            }
        //        }
        //        vertexNum += vertetxCount;
        //        if (i == 0)
        //        {
        //            vertexNormalListStr = curNormalStr;
        //        }
        //        else
        //        {
        //            vertexNormalListStr = "," + curNormalStr;
        //        }
        //    }

        //    if (triangleIdxListStr != "" && vertexPositionListStr != "")
        //    {
        //        suc = true;
        //    }
        //    return suc;
        //}

        private bool ScanCurveInfo(Curve curve, out String curveStr)
        {
            bool suc = false;
            curveStr = null;
            if (curve != null && curve.IsBound)
            {
                IList<XYZ> pntList = curve.Tessellate();
                generator.polylineListString.Clear();
                String str = null;
                int i = 0;
                foreach (XYZ pnt in pntList)
                {
                    if (i == 0)
                    {
                        str = String.Format("{0} {1} {2}",
                            FeetToMm(pnt.X), FeetToMm(pnt.Y), FeetToMm(pnt.Z));
                    }
                    else
                    {
                        str += String.Format(",{0} {1} {2}",
                            FeetToMm(pnt.X), FeetToMm(pnt.Y), FeetToMm(pnt.Z));
                    }
                    i++;
                }
                if (str != null)
                {
                    curveStr = str;
                    generator.polylineListString.Add(str);
                    suc = true;
                }
            }
            return suc;
        }

        String GetParameterInformation(Parameter para, Document document)
        {
            string defName = para.Definition.Name;
            // Use different method to get parameter data according to the storage type
            switch (para.StorageType)
            {
                case StorageType.Double:
                    //covert the number into Metric
                    defName += " : " + para.AsValueString();
                    break;
                case StorageType.ElementId:
                    //find out the name of the element
                    Autodesk.Revit.DB.ElementId id = para.AsElementId();
                    if (id.IntegerValue >= 0)
                    {
                        defName += " : " + document.GetElement(id).Name;
                    }
                    else if (id.IntegerValue == -1)
                    {
                        defName += " : 无";
                    }
                    else
                    {
                        defName += " : " + id.IntegerValue.ToString();
                    }
                    break;
                case StorageType.Integer:
                    if (defName == "工作集")
                    {
                        WorksetTable worksetTable = document.GetWorksetTable();
                        int workTable = para.AsInteger();
                        Workset workset = worksetTable.GetWorkset(new WorksetId(workTable));
                        defName += " : " + workset.Name;
                    }
                    else if (ParameterType.YesNo == para.Definition.ParameterType)
                    {
                        if (para.AsInteger() == 0)
                        {
                            defName += " : " + "否";
                        }
                        else
                        {
                            defName += " : " + "是";
                        }
                    }
                    else
                    {
                        defName += " : " + para.AsInteger().ToString();
                    }
                    break;
                case StorageType.String:
                    defName += " : " + para.AsString();
                    break;
                default:
                    defName = "未知类型";
                    break;
            }

            return defName;
        }

        private Parameter FindParameter(Element element)
        {
            StringBuilder st = new StringBuilder();
            // iterate element's parameters
            foreach (Parameter para in element.Parameters)
            {
                st.AppendLine(GetParameterInformation(para, m_ActiveDocument));
            }
            generator.useParameter = st.ToString();

            Parameter foundParameter = null;
            return foundParameter;
            foreach (Parameter parameter in element.Parameters)
            {
                //BuiltInParameterGroup.PG_MECHANICAL//机械
                //BuiltInParameterGroup.PG_CONSTRAINTS//限制条件
                //BuiltInParameterGroup.PG_GEOMETRY//尺寸标注
                //BuiltInParameterGroup.PG_PHASING//阶段化
                //BuiltInParameterGroup.PG_IDENTITY_DATA//标识数据
                //BuiltInParameterGroup.PG_INSULATION//绝缘层
                if (BuiltInParameterGroup.PG_MECHANICAL == parameter.Definition.ParameterGroup)
                {
                    if (parameter.Definition.Name == "系统类型")
                    {
                        StorageType sType = parameter.StorageType;
                        ElementId parEleID = parameter.AsElementId();
                        Element paraElement = m_ActiveDocument.GetElement(parEleID);
                        if (paraElement is MEPSystemType)
                        {
                            //  PipingSystemType eleFamily = paraElement as PipingSystemType;

                            MEPSystemType eleFamily = paraElement as MEPSystemType;

                            ElementId matId = eleFamily.MaterialId;

                            Material mat = eleFamily.Document.GetElement(matId) as Material;
                            if (mat != null)
                            {
                                Color col = mat.Color;
                                if (col != null)
                                {
                                    String strColor = String.Format("颜色：{0} {1} {2}", col.Red, col.Green, col.Blue);
                                    //     TaskDialog.Show("Color", strColor);
                                }

                                ElementId appearanceAssetId = mat.AppearanceAssetId;
                                AppearanceAssetElement aaEle = eleFamily.Document.GetElement(appearanceAssetId) as AppearanceAssetElement;

                                Asset asset = aaEle.GetRenderingAsset();
                                AssetPropertyDoubleArray4d diffuse = asset["generic_diffuse"] as AssetPropertyDoubleArray4d;


                                double r, g, b;
                                r = diffuse.Value.get_Item(0);
                                g = diffuse.Value.get_Item(1);
                                b = diffuse.Value.get_Item(2);
                                String strColor1 = String.Format("颜色：{0} {1} {2}", r, g, b);
                                //  TaskDialog.Show("Color", strColor1);

                            }

                            Category cat = eleFamily.Category;
                            if (cat != null)
                            {
                                Material matCategory = cat.Material;
                                if (matCategory != null)
                                {
                                    Color colCategory = matCategory.Color;
                                    String strColorCategory = String.Format("{0} {1} {2}", colCategory.Red, colCategory.Green, colCategory.Blue);
                                    TaskDialog.Show("Category颜色", strColorCategory);
                                }
                                else
                                {
                                    CategoryNameMap subCategory = cat.SubCategories;
                                    CategoryNameMapIterator itor = subCategory.ForwardIterator();

                                    itor.Reset();
                                    while (itor.MoveNext())
                                    {
                                        Category obj = itor.Current as Category;
                                        Material matSubCategory = obj.Material;

                                    }
                                }
                            }

                            String parValue = eleFamily.Name;
                        }
                    }
                }
                Definition definition = parameter.Definition;//参数的基类
                //过滤参数
                if (definition.ParameterGroup == BuiltInParameterGroup.PG_MATERIALS &&
                        definition.ParameterType == ParameterType.Material)
                {
                    foundParameter = parameter;
                    break;
                }
            }
            return foundParameter;
        }

        //public void GetMaterial(Document document, FamilyInstance familyInstance)
        //{
        //    Materials materials = document.Settings.Materials;
        //    string str = "";
        //    foreach (Parameter pa in familyInstance.Symbol.Parameters)//通过族符号
        //    {
        //        Definition definition = pa.Definition;//参数的基类
        //        //过滤参数
        //        if (definition.ParameterGroup == BuiltInParameterGroup.PG_MATERIALS &&
        //                definition.ParameterType == ParameterType.Material)
        //        {
        //            Material ma = materials.get_Item(pa.AsElementId());//得到材料参数值的方法
        //            str += definition.Name + ":" + ma.Name + "\n";
        //        }
        //    }
        //    TaskDialog.Show("材质信息", str);
        //}

        private bool CheckHasSolidColor(Element elem, out Color mat)
        {
            mat = null;
            bool bHasColor = false;
            if (mapOverrideEleIdColor.ContainsKey(elem.Id))
            {
                bHasColor = true;
                mat = new Color(mapOverrideEleIdColor[elem.Id].Red,
                    mapOverrideEleIdColor[elem.Id].Green,
                    mapOverrideEleIdColor[elem.Id].Blue);
            }
            return bHasColor;
        }

        private void ApplyColor(Element elem, Material mat)
        {
            //default color
            generator.dR = 128;
            generator.dG = 128;
            generator.dB = 128;
            generator.dA = 0;

            if (mat != null)
            {
                               //     else // 11/6/2013 mwu : do we need this ? 
                    {
                        Color matColor = mat.Color;
                        generator.dR = matColor.Red;
                        generator.dG = matColor.Green;
                        generator.dB = matColor.Blue;
                        generator.dA = mat.Transparency;
                    }

                //test by mwu: 2013/10/30                if (bIsPipeMat)
                {
                    ElementId appearanceAssetId = mat.AppearanceAssetId;
                    AppearanceAssetElement aaEle = m_ActiveDocument.GetElement(appearanceAssetId) as AppearanceAssetElement;
                    if (aaEle != null)
                    {
                        Asset asset = aaEle.GetRenderingAsset();
                        AssetPropertyDoubleArray4d diffuse = asset["generic_diffuse"] as AssetPropertyDoubleArray4d;
                        if (diffuse != null)
                        {
                            double r, g, b, a;
                            r = diffuse.Value.get_Item(0);
                            g = diffuse.Value.get_Item(1);
                            b = diffuse.Value.get_Item(2);
                            a = diffuse.Value.get_Item(3);
                            generator.dR = (int)(r * 255);
                            generator.dG = (int)(g * 255);
                            generator.dB = (int)(b * 255);
                            generator.dA = (int)((1 - a) * 100);
                        }
                    }

                }
                //else
                //{
                //    Color matColor = mat.Color;
                //    generator.dR = matColor.Red;
                //    generator.dG = matColor.Green;
                //    generator.dB = matColor.Blue;
                //    generator.dA = mat.Transparency;
                //}
            }
            //  else //modified by mwu: 2013/11/06, moved out of the function GetElementFacetInfo to preset the default color
            //  {
            //generator.dR = 248;
            //generator.dG = 248;
            //generator.dB = 255;
            //generator.dA = 0;
            //   }

            if (mapOverrideEleIdColor.ContainsKey(elem.Id)) // 10/23/2013 mwu : use the override color 
            {
                generator.dR = mapOverrideEleIdColor[elem.Id].Red;
                generator.dG = mapOverrideEleIdColor[elem.Id].Green;
                generator.dB = mapOverrideEleIdColor[elem.Id].Blue;
                generator.dA = 0;
            }
        }

        private void GetElementFacetInfo(GeometryElement geomElement,
            Transform transform, Color solidColor, double solidTrans,
            bool bSolidHasMaterial, bool bMustSolidColor)
        {
            if (bMustSolidColor)
            {
                bSolidHasMaterial = true;
            }
            //bSolidHasMaterial == true ----> all the faces add to one string
            //bSolidHasMaterial == false ---> every faces write a string then add to string list;

            List<String> faceList = new List<String>();
            List<String> vertexList = new List<String>();
            List<String> normalList = new List<String>();
            List<String> polylineList = new List<String>();
            List<Color> allColorList = new List<Color>();
            List<double> faceTransList = new List<double>();
            //int orgVertexNum = 0;
            //           String curveStr = null;
            //Material curMat = null;
            //if (geomElement != null)
            //{
            //    curMat = geomElement.MaterialElement;

            //    // 10/30/2013 mwu : 
            //    material = curMat;
            //}
            foreach (GeometryObject geomObj in geomElement)
            {
                if (geomObj.Visibility == Visibility.Invisible)
                {
                    continue;
                }

                Mesh mesh = geomObj as Mesh;
                Solid solid = geomObj as Solid;
                Curve curve = geomObj as Curve;

                // 12/18/2013 mwu : test 
               // Instance inst = geomObj as Instance;
                Face face = geomObj as Face;
  //              Element ele = geomObj as Element;


                bool bSolidIsNull = false;
             //   if (null == solid || 0 == solid.Faces.Size ||
      //              0 == solid.Edges.Size)
                    if (null == solid )
                {
                    bSolidIsNull = true;
                }
                if (bSolidIsNull)
                {
                    GeometryInstance instance = geomObj as GeometryInstance;
                    if (null != instance)
                    {
                        GeometryElement instanceGeometry = instance.GetSymbolGeometry();

                        // 12/18/2013 mwu : 
                        if (null == instanceGeometry)
                        {
                            instanceGeometry = instance.GetInstanceGeometry();
                        }

                        if (null == instanceGeometry)
                        {
                            return;
                        }
                        Transform newTransform;
                        if (null == transform)
                        {
                            newTransform = instance.Transform;
                        }
                        else
                        {
                            newTransform = transform.Multiply(instance.Transform);	// get a transformation of the affine 3-space
                        }
                        GetElementFacetInfo(instanceGeometry, newTransform, solidColor,
                            solidTrans, bSolidHasMaterial, bMustSolidColor);
                    }
                    else if (curve != null)
                    {
                        //ScanCurveInfo(curve, out curveStr);
                        //polylineList.Add(curveStr);
                    }
                    //{
                    //    return false;
                    //}
                }
                List<String> faceStrList;
                List<String> vertexStrList;
                List<String> normalStrList;
                List<Color> colorList = new List<Color>();
                if (bSolidHasMaterial && solid != null && !bMustSolidColor)
                {
                    foreach (Face geomFace in solid.Faces)
                    {
                        ElementId matID = geomFace.MaterialElementId;
                        Material tempMaterial = m_ActiveDocument.GetElement(matID) as Material;
                        if (tempMaterial != null)
                        {
                            Color tempColor = tempMaterial.Color;
                            if (tempColor.Red != solidColor.Red ||
                                tempColor.Green != solidColor.Green ||
                                tempColor.Blue != solidColor.Blue)
                            {
                                bSolidHasMaterial = false;
                                break;
                            }
                        }
                    }
                }
                //int vertexNum = 0;
                GetSolidFaceMeshInfo(solid, transform, bSolidHasMaterial, out faceStrList, out vertexStrList, out normalStrList);
                //GetSolidFaceMeshInfoNew(solid, transform, out faceStrList, out vertexStrList, out normalStrList);
                //Added by jsh for solid color
                if (!bSolidHasMaterial && solid != null)
                {
                    foreach (Face geomFace in solid.Faces)
                    {
                        ElementId matID = geomFace.MaterialElementId;
                        Material tempMaterial = m_ActiveDocument.GetElement(matID) as Material;
                        if (tempMaterial != null)
                        {
                            allColorList.Add(tempMaterial.Color);
                            faceTransList.Add(tempMaterial.Transparency);
                            //bSolidHasMaterial = true;

                            // 11/12/2013 mwu : tentative method to set the body color to the face color  
                            //generator.dR = material.Color.Red;
                            //generator.dG = material.Color.Green;
                            //generator.dB = material.Color.Blue;
                            //generator.dA = 0;
                            //break;
                        }
                        else
                        {
                            //Sometime the face don't has material, should use solid color
                            if (solidColor == null)   
                            {
                                solidColor = new Color(128, 128, 128); // default color
                            }
                            allColorList.Add(solidColor);
                            faceTransList.Add(solidTrans);
                        }
                    }
                }

                for (int i = 0; i < faceStrList.Count; ++i)
                {
                    faceList.Add(faceStrList[i]);
                    vertexList.Add(vertexStrList[i]);
                    normalList.Add(normalStrList[i]);
                }

                List<String> MeshfaceStrList;
                List<String> MeshvertexStrList;
                List<String> MeshnormalStrList;
                GetMeshFaceMeshInfo(mesh, transform,
                    out MeshfaceStrList, out MeshvertexStrList, out MeshnormalStrList);
                for (int i = 0; i < MeshfaceStrList.Count; ++i)
                {
                    faceList.Add(MeshfaceStrList[i]);
                    vertexList.Add(MeshvertexStrList[i]);
                    normalList.Add(MeshnormalStrList[i]);
                }

                //orgVertexNum += vertexNum;
            }

            bool bNeedFaceColor = true;
            if (allColorList.Count != faceList.Count)
            {
                bNeedFaceColor = false;
            }
            for (int i = 0; i < faceList.Count; ++i)
            {
                generator.facesListString.Add(faceList[i]);
                generator.vertexListString.Add(vertexList[i]);
                generator.normalListString.Add(normalList[i]);
                if (!bSolidHasMaterial && bNeedFaceColor)
                {
                    generator.faceColorList.Add(allColorList[i]);
                    generator.faceTransList.Add(faceTransList[i]);
                }
            }

            for (int i = 0; i < polylineList.Count; ++i)
            {
                generator.polylineListString.Add(polylineList[i]);
            }
        }

        private void GetFacesAndEdgesOfWall(Wall wall)
        {
            String faceInfo = "";

            Autodesk.Revit.DB.Options opt = new Options();
            Autodesk.Revit.DB.GeometryElement geomElem = wall.get_Geometry(opt);
            foreach (GeometryObject geomObj in geomElem)
            {
                Solid geomSolid = geomObj as Solid;
                if (null != geomSolid)
                {
                    int faces = 0;
                    double totalArea = 0;
                    foreach (Face geomFace in geomSolid.Faces)
                    {
                        faces++;
                        faceInfo += "Face " + faces + " area: " + geomFace.Area.ToString() + "\n";
                        totalArea += geomFace.Area;

                        // Get mesh
                        Mesh mesh = geomFace.Triangulate();
                        for (int i = 0; i < mesh.NumTriangles; i++)
                        {
                            MeshTriangle triangle = mesh.get_Triangle(i);
                            XYZ vertex1 = triangle.get_Vertex(0);
                            XYZ vertex2 = triangle.get_Vertex(1);
                            XYZ vertex3 = triangle.get_Vertex(2);
                        }
                    }
                    faceInfo += "Number of faces: " + faces + "\n";
                    faceInfo += "Total area: " + totalArea.ToString() + "\n";
                    foreach (Edge geomEdge in geomSolid.Edges)
                    {
                        // get wall's geometry edges
                        IList<XYZ> mesh = geomEdge.Tessellate();
                        foreach (XYZ vertex in mesh)
                        {
                            XYZ curVertex = vertex;
                        }
                    }
                }
            }
            TaskDialog.Show("Revit", faceInfo);
        }

        private String GetCategoryName(Category category)
        {
            Category parentCat = category.Parent;
            if (parentCat == null)
            {
                return category.Name;
            }
            else if (category.Name == "墙饰条")
            {
                return category.Name;
            }
            else
            {
                return GetCategoryName(parentCat);
            }
        }

        private Material GetCompoundStructureMaterial(CompoundStructure cs)
        {
            IList<CompoundStructureLayer> csLayers = cs.GetLayers();
            Material mat = null;

//             foreach (CompoundStructureLayer curLayer in csLayers)
//             {
//                 MaterialFunctionAssignment layerFuc = curLayer.Function;
//                 if (layerFuc == MaterialFunctionAssignment.Finish1 ||
//                     layerFuc == MaterialFunctionAssignment.Finish2)
//                 {
//                     ElementId matID = curLayer.MaterialId;
//                     mat = m_ActiveDocument.GetElement(matID) as Material;
//                     break;
//                 }
//             }
//             if (mat == null)
//             {
//                 foreach (CompoundStructureLayer curLayer in csLayers)
//                 {
//                     //MaterialFunctionAssignment layerFuc = curLayer.Function;
//                     //if (layerFuc == MaterialFunctionAssignment.Finish2)
//                     {
//                         ElementId matID = curLayer.MaterialId;
//                         mat = m_ActiveDocument.GetElement(matID) as Material;
//                         break;
//                     }
//                 }
//             }

            foreach (CompoundStructureLayer curLayer in csLayers)
            {
                ElementId matID = curLayer.MaterialId;
                mat = m_ActiveDocument.GetElement(matID) as Material;
                if (mat == null)
                {
                    //Get layer category and subcategory
                    MaterialFunctionAssignment layerFuc = curLayer.Function;

                    //get the category material

                    if (mat != null)
                    {
                        return mat;
                    }
                }
            }

            return mat;
        }

        Material GetOrgWallMaterial(Autodesk.Revit.DB.Document document, Wall wall)
        {
            //CompoundStructureLayer..::..MaterialId Property 
            CompoundStructure cs = wall.WallType.GetCompoundStructure();
            if (cs == null)
            {
                return null;
            }
            IList<CompoundStructureLayer> csLayers = cs.GetLayers();
            Material mat = null;

            foreach (CompoundStructureLayer curLayer in csLayers)
            {
                MaterialFunctionAssignment layerFuc = curLayer.Function;
                if (layerFuc == MaterialFunctionAssignment.Finish1 ||
                    layerFuc == MaterialFunctionAssignment.Finish2)
                {
                    ElementId matID = curLayer.MaterialId;
                    mat = m_ActiveDocument.GetElement(matID) as Material;
                    break;
               }
            }
            if (mat == null)
            {
                foreach (CompoundStructureLayer curLayer in csLayers)
                {
                    //MaterialFunctionAssignment layerFuc = curLayer.Function;
                    //if (layerFuc == MaterialFunctionAssignment.Finish2)
                    {
                        ElementId matID = curLayer.MaterialId;
                        mat = m_ActiveDocument.GetElement(matID) as Material;
                        break;
                    }
                }
            }
            return mat;
        }
        public Material GetWallMaterial(Autodesk.Revit.DB.Document document, Wall wall) 
        {
            Material mat = null;
            // get WallType of wall 
            WallType aWallType = wall.WallType; 
            // Only Basic Wall has compoundStructure Walls, Floors, Roofs and Openings 
            if (WallKind.Basic == aWallType.Kind) 
            { 
                // Get CompoundStructure 
                CompoundStructure comStruct = aWallType.GetCompoundStructure(); 
                Categories allCategories = document.Settings.Categories; 
 
                // Get the category OST_Walls default Material;  
                // use if that layer's default Material is <By Category> 
                Category wallCategory = allCategories.get_Item(BuiltInCategory.OST_Walls); 
                Autodesk.Revit.DB.Material wallMaterial = wallCategory.Material; 
 
                foreach (CompoundStructureLayer structLayer in comStruct.GetLayers()) 
                { 
                    Autodesk.Revit.DB.Material layerMaterial =
                        document.GetElement(structLayer.MaterialId) as Material; 
 
                    // If CompoundStructureLayer's Material is specified, use default 
                    // Material of its Category 
                    if (null == layerMaterial) 
                    { 
                        switch (structLayer.Function) 
                        { 
                            case MaterialFunctionAssignment.Finish1: 
                                layerMaterial =                                        
                                    allCategories.get_Item(BuiltInCategory.OST_WallsFinish1).Material; 
                                break; 
                            case MaterialFunctionAssignment.Finish2: 
                                layerMaterial =                                       
                                    allCategories.get_Item(BuiltInCategory.OST_WallsFinish2).Material; 
                                break; 
                            case MaterialFunctionAssignment.Membrane: 
                                layerMaterial = 
                                    allCategories.get_Item(BuiltInCategory.OST_WallsMembrane).Material; 
                                break; 
                            case MaterialFunctionAssignment.Structure: 
                                layerMaterial =   
                                    allCategories.get_Item(BuiltInCategory.OST_WallsStructure).Material; 
                                break; 
                            case MaterialFunctionAssignment.Substrate: 
                                layerMaterial =  
                                    allCategories.get_Item(BuiltInCategory.OST_WallsSubstrate).Material; 
                                break; 
                            case MaterialFunctionAssignment.Insulation: 
                                layerMaterial =  
                                allCategories.get_Item(BuiltInCategory.OST_WallsInsulation).Material; 
                                break; 
                            default: 
                                // It is impossible to reach here Walls, Floors, Roofs and Openings 
                                break; 
                        } 
                        if (null == layerMaterial) 
                        { 
                            layerMaterial = wallMaterial; 
                        } 
                    } 
                } 
            }

            return mat;
        }
        public Material GetRoofMaterial(Autodesk.Revit.DB.Document document, RoofBase roof)
        {
            Material mat = null;
            // get RoofType of roof 
            RoofType aRoofType = roof.RoofType;
            CompoundStructure comStruct = aRoofType.GetCompoundStructure();
           // Only Basic Wall has compoundStructure Walls, Floors, Roofs and Openings 
            if (comStruct != null)
            {
                // Get CompoundStructure 
                Categories allCategories = document.Settings.Categories;

                // Get the category OST_Walls default Material;  
                // use if that layer's default Material is <By Category> 
                Category roofCategory = allCategories.get_Item(BuiltInCategory.OST_Roofs);
                Autodesk.Revit.DB.Material roofCategoryMaterial = roofCategory.Material;

                foreach (CompoundStructureLayer structLayer in comStruct.GetLayers())
                {
                    Autodesk.Revit.DB.Material layerMaterial =
                        document.GetElement(structLayer.MaterialId) as Material;

                    // If CompoundStructureLayer's Material is specified, use default 
                    // Material of its Category 
                    if (null == layerMaterial)
                    {
                        switch (structLayer.Function)
                        {
                            case MaterialFunctionAssignment.Finish1:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_RoofsFinish1).Material;
                                break;
                            case MaterialFunctionAssignment.Finish2:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_RoofsFinish2).Material;
                                break;
                            case MaterialFunctionAssignment.Membrane:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_RoofsMembrane).Material;
                                break;
                            case MaterialFunctionAssignment.Structure:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_RoofsStructure).Material;
                                break;
                            case MaterialFunctionAssignment.Substrate:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_RoofsSubstrate).Material;
                                break;
                            case MaterialFunctionAssignment.Insulation:
                                layerMaterial =
                                allCategories.get_Item(BuiltInCategory.OST_RoofsInsulation).Material;
                                break;
                            default:
                                // It is impossible to reach here Walls, Floors, Roofs and Openings 
                                break;
                        }
                        if (null == layerMaterial)
                        {
                            layerMaterial = roofCategoryMaterial;
                        } 
                    }
                }
           }
           return mat;
        }

        public Material GetFloorMaterial(Autodesk.Revit.DB.Document document, Floor floor)
        {
            Material mat = null;
            // get FloorType of floor 
            FloorType aFloorType = floor.FloorType;
            // Only Basic Wall has compoundStructure Walls, Floors, Roofs and Openings 
            // Get CompoundStructure 
            CompoundStructure comStruct = aFloorType.GetCompoundStructure();
            if (comStruct != null)
            {
                Categories allCategories = document.Settings.Categories;

                // Get the category OST_Walls default Material;  
                // use if that layer's default Material is <By Category> 
                Category floorCategory = allCategories.get_Item(BuiltInCategory.OST_Floors);
                Autodesk.Revit.DB.Material floorCategoryMaterial = floorCategory.Material;

                foreach (CompoundStructureLayer structLayer in comStruct.GetLayers())
                {
                    Autodesk.Revit.DB.Material layerMaterial =
                        document.GetElement(structLayer.MaterialId) as Material;

                    // If CompoundStructureLayer's Material is specified, use default 
                    // Material of its Category 
                    if (null == layerMaterial)
                    {
                        switch (structLayer.Function)
                        {
                            case MaterialFunctionAssignment.Finish1:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_FloorsFinish1).Material;
                                break;
                            case MaterialFunctionAssignment.Finish2:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_FloorsFinish2).Material;
                                break;
                            case MaterialFunctionAssignment.Membrane:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_FloorsMembrane).Material;
                                break;
                            case MaterialFunctionAssignment.Structure:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_FloorsStructure).Material;
                                break;
                            case MaterialFunctionAssignment.Substrate:
                                layerMaterial =
                                    allCategories.get_Item(BuiltInCategory.OST_FloorsSubstrate).Material;
                                break;
                            case MaterialFunctionAssignment.Insulation:
                                layerMaterial =
                                allCategories.get_Item(BuiltInCategory.OST_FloorsInsulation).Material;
                                break;
                            default:
                                // It is impossible to reach here Walls, Floors, Roofs and Openings 
                                break;
                        }
                        if (null == layerMaterial)
                        {
                            layerMaterial = floorCategoryMaterial;
                        }
                    }
                }
            }
            return mat;
        } 

        Material GetElementMaterial(Element elem)
        {
            //HostObject With CompoundStructure
            bool bHostObjectWithCompoundStructure = false;
            Material mat = null;
            Wall wall = elem as Wall;
            if (wall != null)
            {
                bHostObjectWithCompoundStructure = true;
                mat = GetWallMaterial(m_ActiveDocument, wall);
            }

            RoofBase roof = elem as RoofBase;
            if (roof != null)
            {
                bHostObjectWithCompoundStructure = true;
                mat = GetRoofMaterial(m_ActiveDocument, roof);
            }

            Floor floor = elem as Floor;
            if (floor != null)
            {
                bHostObjectWithCompoundStructure = true;
                mat = GetFloorMaterial(m_ActiveDocument,floor);
            }

            //Ceiling ceiling = elem as Ceiling;
            //if (ceiling != null)
            //{
            //    bHostObjectWithCompoundStructure = true;
            //    mat = GetCeilingMaterial(ceiling);
            //}

            if ( !bHostObjectWithCompoundStructure && mat == null )
            {
                //Is family instance and Material parameter is in its FamilySymbol
                FamilyInstance familyInstance = elem as FamilyInstance;
                if (familyInstance != null)
                {
                    mat = GetMaterialFromParameter(familyInstance);
                }

                if (mat == null)
                {
                    mat = GetMaterialFromCategory(elem);
                }
            }

            return mat;
        }

        Material GetMaterialFromCategory(Element elem)
        {
            Material mat = null;

            Category category = elem.Category;
            mat = category.Material;

            //if (mat == null)
            //{
            //    CategoryNameMap subCategories = category.SubCategories;
            //    if (null != subCategories && 0 != subCategories.Size) // It may be null or has no item in it
            //    {
            //        foreach (Category ii in subCategories)
            //        {
            //            if (null != ii.Material)
            //            {
            //                mat = ii.Material;
            //                break;
            //            }
            //        }
            //    }     
            //}

            return mat;
        }

        Material GetMaterialFromParameter(FamilyInstance familyInstance)
        {
            Material mat = null;

            FamilySymbol familySymbol = familyInstance.Symbol;
            foreach (Parameter parameter in familySymbol.Parameters)
            {
                Definition definition = parameter.Definition;//参数的基类

                if (parameter.Definition.ParameterGroup == BuiltInParameterGroup.PG_MECHANICAL &&
                        definition.ParameterType == ParameterType.Material )
                {
                    if (parameter.Definition.Name == "系统类型")
                    {
                        StorageType sType = parameter.StorageType;
                        ElementId parEleID = parameter.AsElementId();
                        Element paraElement = m_ActiveDocument.GetElement(parEleID);

                        if (paraElement is MEPSystemType)
                        {
                            MEPSystemType eleType = paraElement as MEPSystemType;
                            Material famMat = m_ActiveDocument.GetElement(eleType.MaterialId) as Material;

                            if (famMat != null)
                            {
                                mat = famMat;
                                break;
                            }
                        }
                    }
                }
            }
            
            //    Materials materials = document.Settings.Materials;
            //    string str = "";
            //    foreach (Parameter pa in familyInstance.Symbol.Parameters)//通过族符号
            //    {
            //        Definition definition = pa.Definition;//参数的基类
            //        //过滤参数
            //        if (definition.ParameterGroup == BuiltInParameterGroup.PG_MATERIALS &&
            //                definition.ParameterType == ParameterType.Material)
            //        {
            //            Material ma = materials.get_Item(pa.AsElementId());//得到材料参数值的方法
            //            str += definition.Name + ":" + ma.Name + "\n";
            //        }
            //    }

            return mat;
        }


        Material GetElementMaterial(Element elem, out bool bIsPipeMat)
        {
            bIsPipeMat = false;
            Material mat = null;
            Wall wall = elem as Wall;
            if (wall != null)
            {
                mat = GetWallMaterial(m_ActiveDocument, wall);
            }

            RoofBase roof = elem as RoofBase;
            if (roof != null)
            {
                mat = GetRoofMaterial(m_ActiveDocument, roof);
            }

            Floor floor = elem as Floor;
            if (floor != null)
            {
                mat = GetFloorMaterial(m_ActiveDocument,floor);
            }

//             Ceiling ceiling = elem as Ceiling;
//             if (ceiling != null)
//             {
//                 mat = GetCeilingMaterial(ceiling);
//             }

            if (mat != null)
            {
                return mat;
            }

            MaterialSet matSet = elem.Materials;
            Material firstMat = null;
            int i = 0;
            foreach (Material material in matSet)
            {
                i++;
                //if (firstMat == null)
                if (i == 2)
                {
                    firstMat = material;
                }
                if (matSet.Size == 1)
                {
                    mat = material;
                }
                if (material != null && material.StructuralAssetId.IntegerValue > -1)
                {
                    mat = material;
                    break;
                }
                //double matArea = elem.GetMaterialArea(curMat);
                //double matVolume = elem.GetMaterialVolume(curMat);
            }
            if (mat == null)
            {
                mat = firstMat;
            }

            if (mat == null)
            {
                //mat = new Material();
                //Parameter foundParameter = null;
                foreach (Parameter parameter in elem.Parameters)
                {
                    if (BuiltInParameterGroup.PG_MECHANICAL == parameter.Definition.ParameterGroup)
                    {
                        if (parameter.Definition.Name == "系统类型")
                        {
                            StorageType sType = parameter.StorageType;
                            ElementId parEleID = parameter.AsElementId();
                            Element paraElement = m_ActiveDocument.GetElement(parEleID);
                            if (paraElement is PipingSystemType)
                            {
                                PipingSystemType eleFamily = paraElement as PipingSystemType;

                                Material famMat =
                                    m_ActiveDocument.GetElement(eleFamily.MaterialId) as Material;
                                mat = famMat;
                                bIsPipeMat = true;
                                break;
                            }
                        }
                        else if (parameter.Definition.Name == "管段")
                        {
                            ElementId parEleID = parameter.AsElementId();
                            Element paraElement = m_ActiveDocument.GetElement(parEleID);
                            if (paraElement is PipeSegment)
                            {
                                PipeSegment pipeSegment = paraElement as PipeSegment;
                                Material segMat = m_ActiveDocument.GetElement(pipeSegment.MaterialId) as Material;
                                if (segMat != null)
                                {
                                    //segMat.Color;
                                }
                            }
                        }
                    }
                }
            }

            return mat;
        }

        private void SaveAllVisibleElements(UIApplication app)
        {
            string fileName = XMLDialogManager.SaveDialog();
            if (string.IsNullOrEmpty(fileName))
            {
                return;
            }
            //Step1: Manifest file
            generator.GenerateManifestFile(xml3DfoldPath + @"\Manifest.xml");

            //Setp2: Model structure file WH.3dxml
            XmlElement strNode;
            XmlDocument strDoc = generator.GenerateWH3DXMLFile(out strNode);

            Hashtable catNameIDTable = new Hashtable();
            String curRepFileName = null;

            Document doc = app.ActiveUIDocument.Document;

            FilteredElementCollector collector = null;
            ElementId viewId = FindActiveView(doc, doc.ActiveView.Name);

            if (viewId != ElementId.InvalidElementId)
            {
                collector = new FilteredElementCollector(doc, viewId);
            }
            else
            {
                collector = new FilteredElementCollector(doc);
            }

            collector.WhereElementIsNotElementType();
            FilteredElementIterator iterator = collector.GetElementIterator();
            while (iterator.MoveNext())
            {
                //if (elementIdx == 2208)
                //{
                //    int i = 0;
                //    i++;
                //}
                Element elem = iterator.Current;
                if (elem == null || elem.Category == null)
                {
                    continue;
                }
#if DEBUG
                FindParameter(elem);
#endif
                String catName = GetCategoryName(elem.Category);
                String eleName = elem.Name;
                if (catName == "" || elem.Name == "" || catName == "相机")
                {
                    continue;
                }
                if (catName == "图例构件")
                {
                    continue;
                }
                //if (eleName == "模型线")
                //{
                //}
                //if (catName == "结构柱")
                //{
                //}
                Material mat = null;
               // bool bIsPipeMat = false;
                mat = GetElementMaterial(elem/*, out bIsPipeMat*/);

                ElementId curID = elem.Id;
                int elementID = curID.IntegerValue;

                String eleGUID = elem.UniqueId;
                generator.elementGUID = eleGUID;
                Grid grid = elem as Grid;
                bool hasGridInfo = false;
                bool hasFacetInfo = false;

                //Setp3: Create 3DRep file for each element
                if (grid != null && grid.Curve != null)
                {
                    //String curveStr = null;
                    //generator.polylineListString.Clear();
                    //hasGridInfo = ScanCurveInfo(grid.Curve, out curveStr);
                    //String repName = String.Format(@"\WH_{0}.3DRep", elementIdx++);
                    //curRepFileName = String.Format(@"WH_{0}.3DRep", elementIdx - 1); ;
                    //generator.Generate3DRepFile(xml3DfoldPath + repName);
                }
                else
                {
                    GeometryElement geomElement = elem.get_Geometry(m_ViewOptions);
                    if (geomElement == null)
                    {
                        continue;
                    }
                    if (geomElement.Visibility == Visibility.Invisible)
                    {
                        continue;
                    }
                    generator.facesListString.Clear();
                    generator.vertexListString.Clear();
                    generator.normalListString.Clear();
                    generator.polylineListString.Clear();
                    generator.faceColorList.Clear();
                    generator.faceTransList.Clear();

                    bool bSolidHasMaterial = false;
                    bool bMustSolidColor = false;
                    Color solidColor = null;
                    double solidTrans = 0.0;
                    bMustSolidColor = CheckHasSolidColor(elem, out solidColor);
                    if (mat != null)
                    {
                        ElementId appearanceAssetId = mat.AppearanceAssetId;
                        AppearanceAssetElement aaEle = m_ActiveDocument.GetElement(appearanceAssetId) as AppearanceAssetElement;
                        if (aaEle != null)
                        {
                            Asset asset = aaEle.GetRenderingAsset();
                            AssetPropertyDoubleArray4d diffuse = asset["generic_diffuse"] as AssetPropertyDoubleArray4d;
                            if (diffuse != null)
                            {
                                bMustSolidColor = true;
                            }
                        }
                        solidTrans = mat.Transparency;
                        if (solidColor == null)
                        {
                            solidColor = new Color(mat.Color.Red,
                                mat.Color.Green, mat.Color.Blue);
                        }
                        bSolidHasMaterial = true;
                    }
                    GetElementFacetInfo(geomElement, null, solidColor,
                        solidTrans, bSolidHasMaterial, bMustSolidColor);
                    ApplyColor(elem, mat);

                    if (bSolidHasMaterial == false)
                    {
                    }
//                     else
//                     {
//                         if (mat != null)
//                         {
//                             Color matColor = mat.Color;
//                             generator.dR = matColor.Red;
//                             generator.dG = matColor.Green;
//                             generator.dB = matColor.Blue;
//                             generator.dA = mat.Transparency;
//                         }
//                     }


                    if (generator.facesListString.Count > 0 ||
                        generator.polylineListString.Count > 0)
                    {
                        hasFacetInfo = true;

                        String repFileName = String.Format(@"\WH_{0}.3DRep", elementIdx++);
                        curRepFileName = String.Format(@"WH_{0}.3DRep", elementIdx - 1); ;
                        generator.Generate3DRepFile(xml3DfoldPath + repFileName);
                    }
                }
                if (!hasFacetInfo && !hasGridInfo)
                {
                    continue;
                }

                int curCatID = 0;
                if (catNameIDTable.Contains(catName))
                {
                    curCatID = (int)catNameIDTable[catName];
                }
                else
                {
                    curCatID = generator.AddFamilyNodeToStructure(
                    catName, strDoc, strNode);
                    catNameIDTable.Add(catName, curCatID);
                }
                generator.AddModelNodeToStructure(elem.Name,strDoc, strNode, curCatID, curRepFileName);
            }

            if (strDoc != null)
            {
                strDoc.Save(xml3DfoldPath + @"\WH.3dxml");
            }

            //Step3: Create zip (3dxml) file
            XML3DGenerator.GeneratorStatus suc = generator.CreateZipBy7Zip(xml3DfoldPath, fileName);

            //Step4: Delete all the file on "foldPath"
            DirectoryInfo di = new DirectoryInfo(xml3DfoldPath);
            di.Delete(true);

            if (!string.IsNullOrEmpty(fileName))
            {
                if (suc == XML3DGenerator.GeneratorStatus.SUCCESS)
                {
                    TaskDialog.Show("Revit", "导出3DXML文件成功。");
                }
                else
                {
                    TaskDialog.Show("Revit", "导出3DXML文件失败。");
                }
            }
        }

        private void SaveSelectedElements(ElementSet collection)
        {
            string fileName = XMLDialogManager.SaveDialog();
            if (string.IsNullOrEmpty(fileName))
            {
                return;
            }

            //Step1: Manifest file
            generator.GenerateManifestFile(xml3DfoldPath + @"\Manifest.xml");

            //Setp2: Model structure file WH.3dxml//TODO
            XmlElement strNode;
            XmlDocument strDoc = generator.GenerateWH3DXMLFile(out strNode);

            //List<String> strList = new List<String>();
            Hashtable catNameIDTable = new Hashtable();
            String curRepFileName = null;
            foreach (Element elem in collection)
            {
                if (elem == null)
                {
                    continue;
                }
                ElementId curID = elem.Id;
                int elementID = curID.IntegerValue;
#if DEBUG
                FindParameter(elem);
#endif
                String eleGUID = elem.UniqueId;
                generator.elementGUID = eleGUID;

                Material mat = null;
                bool bIsPipeMat = false;
                mat = GetElementMaterial(elem/*, out bIsPipeMat*/);

                bool hasGridInfo = false;
                bool hasFacetInfo = false;
                Grid grid = elem as Grid;
                //Step3: Create 3dRep file for every element
                if (grid != null && grid.Curve != null)
                {
                    String curveStr = null;
                    generator.polylineListString.Clear();
                    hasGridInfo = ScanCurveInfo(grid.Curve, out curveStr);
                    String repName = String.Format(@"\WH_{0}.3DRep", elementIdx++);
                    curRepFileName = String.Format(@"WH_{0}.3DRep", elementIdx - 1); ;
                    generator.Generate3DRepFile(xml3DfoldPath + repName);
                }
                else
                {
                    GeometryElement geomElement = elem.get_Geometry(m_ViewOptions);
                    if (geomElement == null)
                    {
                        continue;
                    }
                    generator.facesListString.Clear();
                    generator.vertexListString.Clear();
                    generator.normalListString.Clear();
                    generator.polylineListString.Clear();
                    generator.faceColorList.Clear();
                    generator.faceTransList.Clear();

                    bool bSolidHasMaterial = false;
                    bool bMustSolidColor = false;
                    Color solidColor = null;
                    double solidTrans = 0.0;
                    bMustSolidColor = CheckHasSolidColor(elem, out solidColor);
                    if (mat != null)
                    {
                        ElementId appearanceAssetId = mat.AppearanceAssetId;
                        AppearanceAssetElement aaEle = m_ActiveDocument.GetElement(appearanceAssetId) as AppearanceAssetElement;
                        if (aaEle != null)
                        {
                            Asset asset = aaEle.GetRenderingAsset();
                            AssetPropertyDoubleArray4d diffuse = asset["generic_diffuse"] as AssetPropertyDoubleArray4d;
                            if (diffuse != null)
                            {
                                bMustSolidColor = true;
                            }
                        }
                        solidTrans = mat.Transparency;
                        if (solidColor == null)
                        {
                            solidColor = new Color(mat.Color.Red,
                                mat.Color.Green, mat.Color.Blue);
                        }
                        bSolidHasMaterial = true;
                    }

                    GetElementFacetInfo(geomElement, null, solidColor,
                        solidTrans, bSolidHasMaterial, bMustSolidColor);

                    ApplyColor(elem, mat);

                    if (generator.facesListString.Count > 0 ||
                        generator.polylineListString.Count > 0)
                    {
                        hasFacetInfo = true;
                    }
                    String repFileName = String.Format(@"\WH_{0}.3DRep", elementIdx++);
                    curRepFileName = String.Format(@"WH_{0}.3DRep", elementIdx - 1); ;
                    generator.Generate3DRepFile(xml3DfoldPath + repFileName);
                }

                if (!hasFacetInfo && !hasGridInfo)
                {
                    continue;
                }
                String catName = GetCategoryName(elem.Category);
                int curCatID = 0;
                if (catNameIDTable.Contains(catName))
                {
                    curCatID = (int)catNameIDTable[catName];
                }
                else
                {
                    curCatID = generator.AddFamilyNodeToStructure(
                    catName, strDoc, strNode);
                    catNameIDTable.Add(catName, curCatID);
                }
                generator.AddModelNodeToStructure(elem.Name,strDoc, strNode, curCatID, curRepFileName);

                Wall curWall = elem as Wall;
                if (curWall != null)
                {
                    WallType curType = curWall.WallType;
                    string wallStr = curType.Kind.ToString();
                    Utility util = new Utility();
                    XYZ wallDimension = util.GetWallDimensions(m_ActiveDocument, curWall);
                    //info += "\n\t" + "墙体长度：" + wallDimension.X.ToString() + "mm\n\t"
                    //    + "墙体宽度：" + wallDimension.Y.ToString() + "mm\n\t"
                    //    + "墙体高度：" + wallDimension.Z.ToString() + "mm";

                    //facet info
                    //GetFacesAndEdgesOfWall(curWall);
                }
            }
            if (strDoc != null)
            {
                strDoc.Save(xml3DfoldPath + @"\WH.3dxml");
            }

            //Step4: Create zip (3dxml) file
            XML3DGenerator.GeneratorStatus suc = generator.CreateZipBy7Zip(xml3DfoldPath, fileName);

            //Step5: Delete all the file on "foldPath"
            DirectoryInfo di = new DirectoryInfo(xml3DfoldPath);
            di.Delete(true);

#if DEBUG
            if (!string.IsNullOrEmpty(fileName))
            {
                if (suc == XML3DGenerator.GeneratorStatus.SUCCESS)
                {
                    TaskDialog.Show("Revit", "导出3DXML文件成功。");
                }
                else
                {
                    TaskDialog.Show("Revit", "导出3DXML文件失败。");
                }
            }
#endif
            //TaskDialog.Show("构件信息", info);
        }

    }

    class Utility
    {
        public XYZ GetWallDimensions(Document doc, Wall wall)
        {

            //read the wall's name

            string wallName = wall.Name;



            //read the wall's length by reading parameter.            

            LocationCurve lc = wall.Location as LocationCurve;

            double dWallLength = lc.Curve.Length;



            //get wall base absoutely height

            Parameter paramBottomLevel = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT); //base level.

            //get the bottom level id

            ElementId idbottom = paramBottomLevel.AsElementId();

            Level levelBottom = doc.GetElement(idbottom) as Level;

            Parameter paramBotomOffset = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); //base offset.

            double dBottomHeight = levelBottom.Elevation + paramBotomOffset.AsDouble();


            //get wall top absoutely height

            double dHeight = 0;

            Parameter paramTopLevel = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE); //top level.

            if (paramTopLevel != null)
            {

                //get the bottom level id

                ElementId idTop = paramTopLevel.AsElementId();

                Level levelTop = doc.GetElement(idTop) as Level;

                if (levelTop != null)
                {

                    Parameter paramTopOffset = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET); //upper offset.

                    double dHeightTop = levelTop.Elevation + paramTopOffset.AsDouble();



                    //wall height

                    dHeight = dHeightTop - dBottomHeight;

                }

                else

                    dHeight = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();

            }

            //get wall width

            double dWidth = wall.Width;

            dWallLength *= 304.8;
            dWidth *= 304.8;
            dHeight *= 304.8;
            return new XYZ(dWallLength, dWidth, dHeight);

        }
    }
}
